package com.share.common.utils;

import org.slf4j.MDC;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Map;
import java.util.concurrent.*;

public class ThreadUtil {
    private static ThreadPoolTaskExecutor executorService = null;

    static {
        //获取cpu线程数
        int PROCESSORS = Runtime.getRuntime().availableProcessors();

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);//初始化核心线程数
        executor.setMaxPoolSize(50);//最大线程数50：线程池最大的线程数，只有在核心线程用完且缓冲队列满了之后,才会申请非核心线程
        executor.setKeepAliveSeconds(30);//非核心线程在空闲时,达到该时间后会被销毁
        executor.setQueueCapacity(10000);//队列大小---不能太大否则最大线程数 无法使用
        executor.setThreadNamePrefix("async_");

        //设置拒绝策略
        // rejection-policy：当pool已经达到max size的时候，如何处理新任务
        // CALLER_RUNS：不在新线程中执行任务，而是由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        //等待所有任务结束后,再关闭线程池(线程池关闭的时候.等待所有任务都完成,再继续销毁其他的Bean)
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(30);//线程池关闭前,最大等待时间
        executor.initialize();

        executorService = executor;
    }

    //线程持共用
    public static Executor getExecutor() {
        return executorService;
    }


    //Runnable 也是一个lamba函数接口
    public static void execute(Runnable runnable) {
        Map<String, String> context = MDC.getCopyOfContextMap();
        executorService.execute(() -> {
            if (context == null) {
                MDC.clear();
            } else {
                MDC.setContextMap(context);
            }

            try {
                runnable.run();
            } finally {
                MDC.clear();
            }
        });
    }

    //Callable 和 Runnable 都支持,也是一个函数接口
    public static <T> Future<T> submit(Callable<T> callable) {
        Map<String, String> context = MDC.getCopyOfContextMap();
        return executorService.submit(
                () -> {
                    if (context == null) {
                        MDC.clear();
                    } else {
                        MDC.setContextMap(context);
                    }

                    try {
                        return callable.call();
                    } finally {
                        MDC.clear();
                    }
                }
        );
    }

    //Callable 和 Runnable 都支持,也是一个函数接口
    public static <T> T submitAndGet(Callable<T> callable, Long milliTmeOut) {
        T res = null;
        try {
            Future<T> future = submit(callable);
            if (milliTmeOut == null || milliTmeOut <= 0) {
                res = future.get();
            } else {
                res = future.get(milliTmeOut, TimeUnit.MILLISECONDS);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

    public static void shutdown() {
        executorService.shutdown();
    }
}
